#pragma once
#include <vector>
#include "mutexEncapsulation.hpp"
using namespace MutexModule;
#include "semEncapsulation.hpp"
using namespace SemModule;

const int gcap = 5; // for debug

template <typename T>
class RingQueue
{
public:
    // 对于类调用构造函数 要写在初始化列表里面 因为类的构造在构造函数体之前就完成 而函数体内部只是进行赋值
    RingQueue(int cap = gcap)
        : _rq(cap), _cap(cap), _cStep(0), _pStep(0), _dataSem(0), _blankSem(5)
    {
    }
    // 入队列操作
    void Push(T &in)
    {
        // 先申请信号量
        _blankSem.P();
        LockGuard lockguard(&_pMutex);
        {
            // 申请成功说明有资源开始访问
            _rq[_pStep++] = in;
            _pStep %= _cap;
        }
        // 通知另一方 V操作
        _dataSem.V();
    }
    // 出队列操作
    void Pop(T *out)
    {
        _dataSem.P();
        LockGuard lockguard(&_cMutex);
        {
            // 直接移动指针即可 后面数据会覆盖
            *out = _rq[_cStep++];
            _cStep %= _cap;
        }
        _blankSem.V();
    }
    ~RingQueue()
    {
    }

private:
    std::vector<T> _rq;
    int _cap;

    int _cStep;
    int _pStep;

    Sem _dataSem;
    Sem _blankSem;

    Mutex _cMutex;
    Mutex _pMutex;
};